package com.atguigu.spzx.pay.service.impl;

import com.alibaba.fastjson.JSON;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradeWapPayModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradeWapPayRequest;
import com.atguigu.spzx.common.exception.GuiguException;
import com.atguigu.spzx.model.entity.order.OrderInfo;
import com.atguigu.spzx.model.entity.order.OrderItem;
import com.atguigu.spzx.model.entity.pay.PaymentInfo;
import com.atguigu.spzx.model.vo.common.ResultCodeEnum;
import com.atguigu.spzx.order.client.OrderClient;
import com.atguigu.spzx.pay.config.AlipayConfig;
import com.atguigu.spzx.pay.mapper.PaymentInfoMapper;
import com.atguigu.spzx.pay.service.AlipayService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.Date;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@Slf4j
public class AlipayServiceImpl implements AlipayService {
    @Resource
    OrderClient orderClient;
    @Resource
    PaymentInfoMapper paymentInfoMapper;
    @Override
    public String submitAlipay(Long orderNo) {
        //1、根据订单编号查询订单数据
        OrderInfo orderInfo = orderClient.findOrderByOrderNo(orderNo).getData();
        //2、准备支付宝创建表单需要的参数
        String out_trade_no = orderNo.toString();
        //订单名称：使用orderItem的标题拼接字符串
        String subject = StringUtils.join(orderInfo.getOrderItemList().stream().map(OrderItem::getSkuName)
                .collect(Collectors.toList()).toArray());
        String total_amount = orderInfo.getTotalAmount().toString();
        String product_code="QUICK_WAP_WAY";
        //3、封装访问支付宝支付页接口需要的参数
        AlipayTradeWapPayModel model = new AlipayTradeWapPayModel();
        model.setOutTradeNo(out_trade_no);
        model.setSubject(subject);
        model.setTotalAmount(total_amount);
        model.setProductCode(product_code);
        //4、创建alipay客户端对象
        AlipayClient client = new DefaultAlipayClient(
                AlipayConfig.URL,
                AlipayConfig.APPID, AlipayConfig.RSA_PRIVATE_KEY,
                AlipayConfig.FORMAT, AlipayConfig.CHARSET,
                AlipayConfig.ALIPAY_PUBLIC_KEY,AlipayConfig.SIGNTYPE);
        //5、使用客户端发送请求：
        //根据请求参数创建请求对象
        AlipayTradeWapPayRequest alipay_request=new AlipayTradeWapPayRequest();
        alipay_request.setBizModel(model);
        // 设置异步通知地址：支付宝用户支付后  它来调用此接口
        alipay_request.setNotifyUrl(AlipayConfig.notify_url);
        // 设置同步地址
        alipay_request.setReturnUrl(AlipayConfig.return_url);
        // 使用配置好的请求对象  使用客户端发送请求
        try {
            String form = client.pageExecute(alipay_request).getBody();


            //保存交易支付日志：支付成功回调时可以校验支付金额是否正确
            PaymentInfo paymentInfo = new PaymentInfo();
            paymentInfo.setUserId(orderInfo.getUserId());
            paymentInfo.setOrderNo(orderNo.toString());
            paymentInfo.setPayType(2);
//            paymentInfo.setOutTradeNo  支付成功回调时支付宝传入
            paymentInfo.setAmount(orderInfo.getTotalAmount());
            paymentInfo.setContent(subject);
            paymentInfo.setPaymentStatus(0);
            paymentInfo.setCreateTime(new Date());
            paymentInfo.setUpdateTime(new Date());

            paymentInfoMapper.save(paymentInfo);

            return form;
        } catch (AlipayApiException e) {
            e.printStackTrace();
            throw new GuiguException(ResultCodeEnum.UNKNOW_ERROR);
            //失败抛出异常
        }

    }

    @Override
    public PaymentInfo findPaymentInfoByOrderNo(String outTradeNo) {
        return paymentInfoMapper.findPaymentInfoByOrderNo(outTradeNo);
    }

    @Override
    public void updatePaymentInfoById(PaymentInfo paymentInfo) {
        paymentInfoMapper.updatePaymentInfoById(paymentInfo);
    }

    @Override
    public String notifyUrl(Map<String, String> params) {

        //异步通知代表支付宝支付的最终状态
        //获取支付宝的通知返回参数，可参考技术文档中页面跳转同步通知参数列表(以下仅供参考)//
        //商户订单号
        String out_trade_no = params.get("out_trade_no");
        //支付宝交易号
        String trade_no = params.get("trade_no");
        //交易状态
        String trade_status = params.get("trade_status");
        //支付金额
        String total_amount = params.get("total_amount");
        //获取支付宝的通知返回参数，可参考技术文档中页面跳转同步通知参数列表(以上仅供参考)//
        //计算得出通知验证结果
        boolean verify_result = false;
        try {
            verify_result = AlipaySignature.rsaCheckV1(params, AlipayConfig.ALIPAY_PUBLIC_KEY, AlipayConfig.CHARSET, "RSA2");
            //校验参数是否被篡改
            if(!verify_result){
                log.error("支付宝支付回调失败,验签失败");
                //验签失败：数据或者签名被修改
                return "fail";
            }
            //校验支付的转态是否为支付成功
            if(!"TRADE_SUCCESS".equals(trade_status)){
                log.error("订单状态不能支付，status:"+trade_status);
                //验签失败：数据或者签名被修改
                return "fail";
            }
            //使用orderNo查询支付记录: 封装提交支付宝支付表单时，需要保存交易日志
            PaymentInfo paymentInfo = findPaymentInfoByOrderNo(out_trade_no);
            //如果支付日志的状态不是0 表示当前订单已经处理过
            if(paymentInfo.getPaymentStatus().intValue()!=0){
                //已经处理过
                return "success";
            }
            // 验证支付金额是否正确
            if(!paymentInfo.getAmount().equals(new BigDecimal(total_amount))){
                //支付金额错误
                log.error("订单状态不能支付，支付金额错误 , 应付金额{}，实付金额{}",paymentInfo.getAmount()
                        ,total_amount);
                return "fail";
            }
            // 更新支付日志
            paymentInfo.setPaymentStatus(1);
            paymentInfo.setOutTradeNo(trade_no);
            paymentInfo.setCallbackTime(new Date());
            paymentInfo.setCallbackContent(JSON.toJSONString(params));
            //更新订单的支付状态
            updatePaymentInfoById(paymentInfo);
            // 更新订单状态（订单状态、销量库存）
            orderClient.updateOrderByOrderNo(Long.parseLong(paymentInfo.getOrderNo()));


            return "success";
        } catch (AlipayApiException e) {
            e.printStackTrace();
            //throw new RuntimeException(e);
            return "fail";
        }

    }

    @Override
    public String returnUrl(Map<String, String> params) {
        //同步通知是支付宝为了让用户快速得到支付结果 让用户支付后客户端跳转访问的接口地址
        //此接口被访问时支付可能仍未成功，以异步的结果为准
        //同步通知主要判断 用户支付是否出现异常，最基本参数是否安全....
        //如果校验成功，跳转到支付成功页
        //如果校验失败，跳转到支付失败页面
        //获取支付宝的通知返回参数，可参考技术文档中页面跳转同步通知参数列表(以下仅供参考)//
        //商户订单号
        String out_trade_no = params.get("out_trade_no");
        //支付宝交易号
        String trade_no = params.get("trade_no");

        //获取支付宝的通知返回参数，可参考技术文档中页面跳转同步通知参数列表(以上仅供参考)//
        //计算得出通知验证结果
        //boolean AlipaySignature.rsaCheckV1(Map<String, String> params, String publicKey, String charset, String sign_type)
        try {
            boolean verify_result = AlipaySignature.rsaCheckV1(params, AlipayConfig.ALIPAY_PUBLIC_KEY,
                    AlipayConfig.CHARSET, "RSA2");

            if(verify_result){//验证成功
                //////////////////////////////////////////////////////////////////////////////////////////
                //请在这里加上商户的业务逻辑程序代码
                //该页面可做页面美工编辑
                //返回重定向视图，客户端会自动重定向访问地址  跳转回前端项目
                return "redirect:http://192.168.1.170/#/pages/order/order?state=0";
            }else{
                //该页面可做页面美工编辑
                //验签失败
            }
        } catch (AlipayApiException e) {
//            throw new RuntimeException(e);
        }
        //如果上面处理后没有返回：重定向到错误页
        return "redirect:http://192.168.1.170:80";
    }
}
